<!-- 斜面反弹 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>斜面反弹</title>
    <style>
        canvas {
            background-color: black;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script src="../utils.js"></script>
<script>
    // 小球绘制
    class Ball {
        constructor(options) {
            this.x = 0;
            this.y = 0;
            this.r = 200;
            this.fillStyle = 'blue';
            this.strokeStyle = 'black';
            // 小球缩放
            this.scaleX = 1;
            this.scaleY = 1;
            // 定义小球移动速度
            this.vx = 0;
            this.vy = 0;
            // 小球透明度
            this.alpha = 1;
            Object.assign(this, options);
            return this;
        }
        render(ctx) {
            let { x, y, r, fillStyle, strokeStyle, scaleX, scaleY, alpha } = this;
            // 保存绘图环境
            ctx.save();
            // 开始绘制
            // ctx.beginPath();
            ctx.beginPath();
            ctx.translate(x, y);
            ctx.scale(scaleX, scaleY);
            ctx.strokeStyle = strokeStyle;
            ctx.fillStyle = fillStyle;

            ctx.globalAlpha = alpha;

            ctx.arc(0, 0, r, 0, Math.PI * 2);


            ctx.fill();
            ctx.stroke();
            ctx.restore();
            ctx.closePath();
            return this;
        }
        // 判断点是否在图形内部
        isInside(x, y) {
            let dis = Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2))
            return dis < this.r;
        }
    }

    // 直线类
    class Line {
        constructor(options) {
            this.x1 = 0;
            this.y1 = 0;
            this.x2 = 0;
            this.y2 = 0;
            this.x = 0;
            this.y = 0;
            this.rotation = 0;
            this.strokeStyle = 'black';
            this.lineWidth = 1;
            Object.assign(this, options);
            return this;
        }
        render(ctx) {
            ctx.save();
            ctx.strokeStyle = this.strokeStyle;
            ctx.lineWidth = this.lineWidth;
            ctx.translate(this.x, this.y);
            ctx.rotate(this.rotation);
            ctx.beginPath();
            ctx.moveTo(this.x1, this.y1);
            ctx.lineTo(this.x2, this.y2);
            ctx.stroke();
            ctx.restore();
            return this;
        }
    }

    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    let w = canvas.width = 800;
    let h = canvas.height = 800;

    let ball = new Ball({
        x: 150,
        y: 200,
        r: 40,
        fillStyle: 'red',
        strokeStyle: 'black',
        scaleX: 1,
        scaleY: 1,
        alpha: 1,
        vy: 1,
    });

    // 实例化斜面
    let line = new Line({
        x1: 0,
        y1: 0,
        x2: 400,
        y2: 0,
        x: 120,
        y: 560,
        rotation: c.toRad(10),
        lineWidth: 3,
        strokeStyle: 'rgb(227, 40, 141)'
    });

    // 重力加速度
    let g = 0.05;
    // 反弹系数
    let bounce = -0.8;

    /**
     * 检测球是否碰到斜面
     * @param {Ball} ball 球
     */
    let sin = Math.sin(line.rotation), cos = Math.cos(line.rotation);
    function checkBlot(ball) {
        // // 假设相对于原点进行旋转
        // let dx = ball.x - line.x;
        // let dy = ball.y - line.y;
        // // 小球旋转后的坐标为（假设进行顺时针旋转）
        // let x1 = dx * Math.cos(line.rotation) - dy * Math.sin(line.rotation);
        // let y1 = dx * Math.sin(line.rotation) + dy * Math.cos(line.rotation);
        // // 对小球的速度进行旋转
        // let vx1 = dx * Math.cos(line.rotation) - dy * Math.sin(line.rotation);
        // let vy1 = dx * Math.sin(line.rotation) + dy * Math.cos(line.rotation);

        // // 进行碰撞检测
        // if (y1 + ball.r >= 0) {
        //     y1 = -ball.r;
        //     vy1 *= bounce;
        // }

        // // 将系统旋转回去
        // let x2 = x1 * Math.cos(line.rotation) - y1 * Math.sin(line.rotation);
        // let y2 = y1 * Math.cos(line.rotation) - x1 * Math.sin(line.rotation);
        // ball.vx = vx1 * Math.cos(line.rotation) - vy1 * Math.sin(line.rotation);
        // ball.vy = vy1 * Math.cos(line.rotation) + vx1 * Math.sin(line.rotation);

        // ball.x = x2 - line.x;
        // ball.y = y2 - line.y;
        // console.log('a', ball.x, ball.y, ball.vx, ball.vy)
        // 获取小球相对于中心点的坐标
        let rx = ball.x - line.x;
        let ry = ball.y - line.y;

        // 对小球的坐标点进行旋转
        let x1 = rx * cos + ry * sin;
        let y1 = ry * cos - rx * sin;

        // 对小球的速度进行旋转
        let vx1 = ball.vx * cos + ball.vy * sin;
        let vy1 = ball.vy * cos - ball.vx * sin;

        // 检测小球和水平直线的碰撞
        if (x1 + ball.r > line.x1 && x1 - ball.r < line.x2) { // 落在斜线上才碰撞
            // 上边界
            if (y1 + ball.r > 0 && vy1 > y1) {
                y1 = -ball.r;
                vy1 *= bounce;
            }
            // 下边界
            if (y1 - ball.r < 0 && vy1 < y1) {
                y1 = ball.r;
                vy1 *= bounce;
            }
        }


        // 将整个系统旋转回初始的位置
        rx = x1 * cos - y1 * sin;
        ry = y1 * cos + x1 * sin;

        // 将速度旋转回去
        ball.vx = vx1 * cos - vy1 * sin;
        ball.vy = vy1 * cos + vx1 * sin;
        // 相对于斜线旋转的，进行坐标计算
        ball.x = line.x + rx;
        ball.y = line.y + ry;
    }


    (function move() {
        window.requestAnimationFrame(move);
        ctx.clearRect(0, 0, w, h);
        ball.vy += g;
        ball.y += ball.vy;
        ball.x += ball.vx;


        // 边界检测
        c.checkBallBounce(ball, w, h, bounce);

        // 斜面检测
        checkBlot(ball);


        ball.render(ctx);
        line.render(ctx);
    })()

</script>

</html>